#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "mpi.h"

#define run_times 1
#define test_times 1000
#define NUM_MACHINES 32

double times[run_times];
FILE *fp;
void output(struct rusage* usage);

void init_mpi(char *fileprefix)
{
    char filename[30];
    sprintf(filename, "%s_%d", fileprefix, NUM_MACHINES);
    fp = fopen(filename, "w");
    if (fp == NULL) {
        printf("Can't open input file %s\n", filename);
        exit(1);
    }
    memset(times, 0, sizeof(times));
    puts("test init done");
}

void test_mpi(int run, int nump, 
              void (*init)(int,int), 
              void (*barrier)(void))
{
    int i, t, rank;
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &nump);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    init(nump, rank);
    printf("test_mpi: machine %d\n", rank);
    t = 0;
    long begin = clock();
    while (t++ < test_times) {
        barrier();
    }
    long finish = clock();
    times[run] = (double)(finish - begin) / CLOCKS_PER_SEC / test_times;

    MPI_Finalize();
    printf("machine %d finalized\n", rank);
}

void run_mpi(void (*init)(int, int), void (*barrier)(void))
{
    int i, j;
    for (i=0; i<run_times; ++i)
        test_mpi(i, NUM_MACHINES, init, barrier);
}

void printout(int top)
{
    int j;
    double average = 0.0;
    for (j=0; j<run_times; ++j) average += times[j];
    average /= run_times;
    fprintf(fp, "num_of_machines\n%d\navearge:\n%.10lf\n", NUM_MACHINES, average);

    struct rusage usage;
    getrusage(RUSAGE_SELF, &usage);
    output(&usage);
}

void output(struct rusage* usage)
{
    fprintf(fp, "user time used:\n%ld.06%ld\n", usage->ru_utime.tv_sec, usage->ru_utime.tv_usec);
    fprintf(fp, "system time used:\n%ld.%ld\n", usage->ru_stime.tv_sec, usage->ru_stime.tv_usec);
    fprintf(fp, "maximum resident set size:\n%ld\n", usage->ru_maxrss);
    fprintf(fp, "integral shared memory size:\n%ld\n", usage->ru_ixrss);
    fprintf(fp, "integral unshared data size:\n%ld\n", usage->ru_idrss);
    fprintf(fp, "integral unshared stack size:\n%ld\n", usage->ru_isrss);
    fprintf(fp, "page reclaims:\n%ld\n", usage->ru_minflt);
    fprintf(fp, "page faults:\n%ld\n", usage->ru_majflt);
    fprintf(fp, "swaps:\n%ld\n", usage->ru_nswap);
    fprintf(fp, "block input operations:\n%ld\n", usage->ru_inblock);
    fprintf(fp, "block output operations:\n%ld\n", usage->ru_oublock);
    fprintf(fp, "message sent:\n%ld\n", usage->ru_msgsnd);
    fprintf(fp, "message received:\n%ld\n", usage->ru_msgrcv);
    fprintf(fp, "signals received:\n%ld\n", usage->ru_nsignals);
    fprintf(fp, "voluntary context switches:\n%ld\n", usage->ru_nvcsw);
    fprintf(fp, "involuntary context switches:\n%ld\n", usage->ru_nivcsw);
}

